{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "8ee17936",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83e7d0b7",
   "metadata": {},
   "source": [
    "### 创建一个随机的非线性映射"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "4e409967",
   "metadata": {},
   "outputs": [],
   "source": [
    "def sigmoid(x):\n",
    "    return 1/(1 + np.exp(-x))\n",
    "\n",
    "def relu(x):\n",
    "    x[x < 0] = 0\n",
    "    return x\n",
    "\n",
    "\n",
    "def simple_nn(x, hidden_layers=[]):\n",
    "    m = x.shape[1]\n",
    "    for idx, n in enumerate(hidden_layers[:-1]):\n",
    "        np.random.seed(idx)\n",
    "        w = np.random.randn(m, n)\n",
    "        np.random.seed(idx * 5 + 77)\n",
    "        b = np.random.randn(1, n)\n",
    "        # print(w.shape, b.shape)\n",
    "        x = relu(x @ w + b)\n",
    "        m = x.shape[1]\n",
    "    \n",
    "    n = hidden_layers[-1]\n",
    "    np.random.seed(88)\n",
    "    w = np.random.randn(m, n)\n",
    "    np.random.seed(88 * 5 + 77)\n",
    "    b = np.random.randn(1, n)\n",
    "    # print(w.shape, b.shape)\n",
    "    x = sigmoid(x @ w + b)\n",
    "    return x\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8303a4e",
   "metadata": {},
   "source": [
    "### 利用上述非线性映射创建数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "8dbbb03c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1000, 3)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([440])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.random.seed(555)\n",
    "x = np.random.uniform(-10, 10, (1000, 3))\n",
    "\n",
    "x = (x - x.mean(axis=0)) / x.std(axis=0)\n",
    "print(x.shape)\n",
    "y = simple_nn(x, [32, 50, 1]) >= 0.5\n",
    "sum(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "73d0cda9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.69198025, -1.51343228,  1.5130557 ,  1.        ],\n",
       "       [ 0.58375783,  0.32825498, -1.25551369,  0.        ],\n",
       "       [ 1.4767416 , -0.50467645,  0.39416693,  0.        ],\n",
       "       ...,\n",
       "       [ 1.28928677, -0.15199359, -1.44119827,  0.        ],\n",
       "       [ 0.53293716,  0.22109142, -0.50369123,  0.        ],\n",
       "       [ 0.63577087, -0.86270905, -1.1639847 ,  0.        ]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dataset = np.c_[x, y]\n",
    "dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "524fe74b",
   "metadata": {},
   "source": [
    "### 划分训练集和测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "77fcfe7e",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "np.random.seed(83)\n",
    "train_index = np.random.choice(list(range(len(dataset))), 800, replace=False)\n",
    "\n",
    "dataset[train_index]\n",
    "test_index = list(set(range(len(dataset))) - set(train_index))\n",
    "# test_index"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f4c3489",
   "metadata": {},
   "source": [
    "$y = \\frac{1}{1 + e^{-x}}$\n",
    "\n",
    "$x = ln{((\\frac{1-y}{y})^{-1})} = Ln(\\frac{y}{1-y})$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "12bb6004",
   "metadata": {},
   "outputs": [],
   "source": [
    "def arc_sigmoid(y):\n",
    "    return np.clip(np.log(y / (1 - y + 1e-5) + 1e-5) , a_min=-10, a_max=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1fcd497",
   "metadata": {},
   "source": [
    "### 设计非梯度的优化方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "d8740dc9",
   "metadata": {},
   "outputs": [],
   "source": [
    "def solve_left_value(A, B):\n",
    "    I = (A @ A.T)\n",
    "    return B @ A.T @ np.linalg.inv(I + 1e-5 * np.eye(I.shape[0]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "1edc8f5a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def solve_right_value(A, B):\n",
    "    I = A.T @ A\n",
    "    return np.linalg.inv(I + 1e-5 * np.eye(I.shape[0])) @ A.T @ B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "2910cb50",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "def solve_network(x, y, weights, biases, arc_actv, actv,lr):\n",
    "    yp = y\n",
    "    yt = []\n",
    "    for w, b, a in zip(weights[:0:-1], biases[:0:-1], arc_actv[:0:-1]):\n",
    "        #print(np.r_[w,b].shape, a)\n",
    "        yt.append(a(yp))\n",
    "        yp = solve_left_value(np.r_[w, b],  yt[-1])[:, :-1]\n",
    "    yp = arc_actv[0](yp)\n",
    "    yt.append(yp)\n",
    "    x0 = x\n",
    "    for idx, (yp, a) in enumerate(zip(yt[::-1], actv)):\n",
    "        x0 = np.c_[x0, np.ones(( x0.shape[0],1))]\n",
    "    #     print(x0.shape, yp.shape)\n",
    "        w = solve_right_value(x0, yp)\n",
    "        weights[idx] = weights[idx] * (1 - lr) + lr * w[:-1,:]\n",
    "        biases[idx] = biases[idx] *(1-lr) + lr * w[-1,:]\n",
    "\n",
    "        x0 = a(x0 @ w)\n",
    "        # print(f\"val:{x0.shape, yp.shape, w.shape}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "3374a53b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def bce(p, y):\n",
    "    return (- y * np.log(p + 1e-5) - ( 1-y) * np.log(1-p + 1e-5)).mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "6b793a3e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def forward(x, weights, biases, actv):\n",
    "    for w, b, a in zip(weights, biases, actv):\n",
    "        x = a(x @ w + b)\n",
    "    return x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29b61adb",
   "metadata": {},
   "source": [
    "### 全量数据直接计算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "327759ed",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[505] 5.670358791670487\n",
      "[507] 5.60314050137305\n",
      "[510] 5.133630587292677\n",
      "[518] 5.441449578861037\n",
      "[552] 4.7468688016834415\n",
      "[671] 2.6334727705858434\n",
      "[853] 0.671244495115185\n",
      "[914] 0.2586622091148325\n",
      "[919] 0.21743380308766883\n",
      "[923] 0.21267253066362035\n",
      "[923] 0.2117971619342382\n",
      "[924] 0.21155363134833582\n",
      "[924] 0.21146190694091027\n",
      "[924] 0.21141794965530586\n",
      "[924] 0.21139870175200387\n",
      "[924] 0.21138834372955853\n",
      "[924] 0.21137954628565261\n",
      "[924] 0.21137253530205552\n",
      "[924] 0.21136819123644346\n",
      "[924] 0.21136565218912484\n",
      "[924] 0.21136425016602728\n",
      "[924] 0.21136350600428314\n",
      "[924] 0.21136311896582705\n",
      "[924] 0.21136292578973112\n",
      "[924] 0.2113628335722993\n",
      "[924] 0.2113627934005909\n",
      "[924] 0.21136278246780868\n",
      "[924] 0.2113627858106292\n",
      "[924] 0.21136279604831912\n",
      "[924] 0.21136281296660347\n",
      "[924] 0.2113628292044579\n",
      "[924] 0.21136284801170394\n",
      "[924] 0.2113628682627074\n",
      "[924] 0.21136288754130833\n",
      "[924] 0.2113629070446487\n",
      "[924] 0.21136292823622022\n",
      "[924] 0.21136294915145537\n",
      "[924] 0.21136296890763373\n",
      "[924] 0.21136299059639083\n",
      "[924] 0.21136301276150932\n",
      "[924] 0.21136303214315483\n",
      "[924] 0.211363051791343\n",
      "[924] 0.21136307391670447\n",
      "[924] 0.21136309488636199\n",
      "[924] 0.21136311598583724\n",
      "[924] 0.21136313770339907\n",
      "[924] 0.21136315916361623\n",
      "[924] 0.21136318209899393\n",
      "[924] 0.21136320392252744\n",
      "[924] 0.21136322554686868\n"
     ]
    }
   ],
   "source": [
    "weights = [np.ones((3, 32)), np.ones((32, 50)), np.ones((50, 1))]\n",
    "biases = [np.zeros((1, 32)), np.zeros((1, 50)), np.zeros((1, 1))]\n",
    "arc_actv = [np.arctanh, np.arctanh, arc_sigmoid]\n",
    "actv = [np.tanh, np.tanh, sigmoid]\n",
    "\n",
    "for epoch in range(50):\n",
    "    solve_network(x, y, weights, biases, arc_actv, actv, 0.5)\n",
    "    y2 = forward(x, weights, biases, actv)\n",
    "    print(sum((forward(x, weights, biases, actv) > 0.5) == y), bce(y2, y.astype(int).reshape((-1, 1))))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc8f7318",
   "metadata": {},
   "source": [
    "### 批量计算，验证泛化能力"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "eee01f36",
   "metadata": {},
   "outputs": [],
   "source": [
    "def batch_data(data, batchsize):\n",
    "    n_batch = data.shape[0] // batchsize\n",
    "    for k in range(n_batch):\n",
    "        batch = data[k * batchsize : (k+1) * batchsize]\n",
    "        yield batch[:, :-1], batch[:, -1].reshape((-1, 1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "7ab5d0e5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAAHFCAYAAAAaD0bAAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABLl0lEQVR4nO3deVyVZf7/8fdhPaCAisiSiNC44Ra5a5am4mjaNDOl05jLZNPP0lKpZiK1UVssy8al1HHG4muNpo1LOpqKqVBJiwZOU1aWC6Qw7hxBQYH794dx8sQiIHBzOK/n43E/pnNxnft87nMO8p7rvu7rthiGYQgAAMCFuJldAAAAQG0jAAEAAJdDAAIAAC6HAAQAAFwOAQgAALgcAhAAAHA5BCAAAOByCEAAAMDlEIAAAIDLIQChRuzZs0czZ87UuXPnamT/48aNU8uWLav03ISEBFksFh05cqRaa6qImTNnymKx6NSpU9fs27JlS40bN65S+6/p9/16TZ8+XS1atJCHh4caNWpkdjkuq1+/furXr5/98ZEjR2SxWJSQkFCjr7ty5UrNnz+/Rl+jKr766ivNnDmz1H8T+vXrpw4dOtR4DbX1GeAnBCDUiD179mjWrFk19od4xowZWr9+fZWee8cddyglJUWhoaHVXFX1Wr9+vWbMmFGp59T0+3493n33XT333HMaM2aMkpKStGPHDrNLwo9CQ0OVkpKiO+64o0Zfpy4HoFmzZpnyf4pgHg+zCwAk6eLFi/Lx8alw/xtvvLHKrxUUFKSgoKAqP7+2xMTEmF2C3YULF+Tr63td+/jvf/8rSXr00UfVrFmz6iirWupyJpX9Pakob29v9ezZs9r3C9RljACh2s2cOVNPPPGEJCkyMlIWi0UWi0W7d++WdOXUzrBhw7Ru3TrFxMTIarVq1qxZkqTXXntNt956q5o1a6YGDRqoY8eOmjt3ri5fvuzwGqWdArNYLJo0aZLefPNNtWvXTr6+vurcubP+/e9/O/Qr7RRY8TD3Z599pr59+8rX11dRUVF64YUXVFRU5PD8L7/8UrGxsfL19VVQUJAmTpyozZs3Oxzjtfzvf//Tvffeq4CAAAUHB+v+++9Xdna2Q5+fnwIrKirSs88+qzZt2sjHx0eNGjVSp06dtGDBggq970VFRZo7d67atm0rb29vNWvWTGPGjNEPP/zg8LrF70VycrJ69+4tX19f3X///Ro/fryaNGmiCxculDie22+/Xe3bty/zeFu2bKnp06dLkoKDg2WxWDRz5sxqqass48aNU8OGDfXdd99p6NChatiwocLDw/XYY48pPz/foe+ZM2f08MMP64YbbpCXl5eioqI0bdq0Ev0q+h0rz4cffqhevXrJarXqhhtu0IwZM/SPf/yjxHeyOn5PDMPQ3LlzFRERIavVqptvvlnvvfdeiZrKOv1y8OBB/f73v1ezZs3k7e2tdu3a6bXXXnPos3v3blksFq1atUrTpk1TWFiY/P39NXDgQH3zzTf2fv369dPmzZt19OhR+3fTYrGU+14Vvwf//ve/FRMTIx8fH7Vr187+fickJKhdu3Zq0KCBunfvrr1795bYx969e3XnnXeqSZMmslqtiomJ0Zo1a+w/T0hI0D333CNJ6t+/v72un78XFfm3IT09Xffdd5/D+zVv3rwS/Y4fP64RI0bIz89PAQEBGjlypLKyssp9L1ADDKCaZWRkGI888oghyVi3bp2RkpJipKSkGNnZ2YZhGEZERIQRGhpqREVFGa+//rqxa9cu49NPPzUMwzCmTp1qLFmyxNi6dauxc+dO469//avRtGlT4w9/+IPDa4wdO9aIiIhwaJNktGzZ0ujevbuxZs0aY8uWLUa/fv0MDw8P4/vvv7f3e+ONNwxJxuHDh+1tt912mxEYGGi0atXKWLp0qZGYmGg8/PDDhiTj//7v/+z9jh8/bgQGBhotWrQwEhISjC1bthijR482WrZsaUgydu3aVe5785e//MWQZLRp08Z4+umnjcTEROOVV14xvL29SxxjRESEMXbsWPvjOXPmGO7u7sZf/vIX4/333ze2bt1qzJ8/35g5c2aF3vcHH3zQkGRMmjTJ2Lp1q7F06VIjKCjICA8PN06ePOnwXjRp0sQIDw83Fi1aZOzatctISkoy9u/fb0gy/v73vzvU+eWXXxqSjNdee63M4/7888+N8ePHG5KMrVu3GikpKUZGRka11FWWsWPHGl5eXka7du2Ml19+2dixY4fx9NNPGxaLxZg1a5a938WLF41OnToZDRo0MF5++WVj+/btxowZMwwPDw9j6NChDvus6HesLPv37zesVqvRqVMn4+233zY2btxoDB061P79ufo7WR2/J8Xft/HjxxvvvfeesWzZMuOGG24wQkJCjNtuu83e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r776yj4PqCwWi0XSlTlExf9dzDAM+3/7+PhUqJarT2kV76+4vpkzZ+rLL7/UHXfcoZ07dyo6Olrr16+v0H4BmIsABKDOiY6Olre3t9LT0/WLX/zCYQsPD7f3+/jjj+3/ffbsWX377bdq27atfR8ffvihw3737Nmj1q1by93dXR07dlRRUZGSkpKuq9bWrVtr6tSp2r59u37zm9/ojTfeuK79AagdTIIGUOf4+fnp8ccf19SpU1VUVKRbbrlFNptNe/bsUcOGDRURESFJmj17tgIDAxUcHKxp06apadOmuuuuuyRJjz32mLp166ZnnnlGI0eOVEpKil599VUtXrxYktSyZUuNHTtW999/v30S9NGjR3XixAmNGDHimjVevHhRTzzxhO6++25FRkbqhx9+0Geffabf/va3Nfa+AKhGZk9CAoDSFBUVGQsWLDDatGljeHp6GkFBQcbgwYONpKQk+wTlTZs2Ge3btze8vLyMbt26GWlpaQ77+Ne//mVER0cbnp6eRosWLYyXXnrJ4ecXL140pk6daoSGhhpeXl7GL37xC+P11183DOOnSdBnz561909NTTUkGYcPHzby8/ON3/3ud0Z4eLjh5eVlhIWFGZMmTbJPkAZQt1kM46qT4gDgBHbv3q3+/fvr7NmzatSokdnlAHBCzAECAAAuhwAEAABcDqfAAACAy2EECAAAuBwCEAAAcDkEIAAA4HIIQAAAwOUQgAAAgMshAAEAAJdDAAIAAC6HAAQAAFwOAQgAALic/w91zM7N86ZKNQAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "weights = [np.ones((3, 32)), np.ones((32, 50)), np.ones((50, 1))]\n",
    "biases = [np.zeros((1, 32)), np.zeros((1, 50)), np.zeros((1, 1))]\n",
    "arc_actv = [np.arctanh, np.arctanh, arc_sigmoid]\n",
    "actv = [np.tanh, np.tanh, sigmoid]\n",
    "\n",
    "mean_loss1 = []\n",
    "\n",
    "for epoch in range(10):\n",
    "    loss_array = []\n",
    "    for x, y in batch_data(dataset[train_index], 50):\n",
    "        #print(x.shape, y.shape)\n",
    "        solve_network(x, y.reshape((-1, 1)), weights, biases, arc_actv, actv, 0.5)\n",
    "        p = forward(x, weights, biases, actv) \n",
    "        loss_array.append(bce(p, y.astype(int).reshape((-1, 1))))\n",
    "    mean_loss1.append(np.array(loss_array).mean())\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "plt.plot(range(len(mean_loss1)), mean_loss1)\n",
    "plt.xlabel(\"epochs\")\n",
    "plt.ylabel(\"bce loss\")\n",
    "plt.title(\"training history for non-gradient method\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "198d3c5f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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hISECDMzMzFixAhx5coV8ffff4tly5YJlUol/ve//0n7vX37VjRs2FDY2tqKZcuWiStXroj79++L7du3i5o1a4rg4OAM832MlJQUUblyZdG8eXNx+fJlcfToUVG8eHExatQoaZsnT56ITz75RJw/f16q+fv7i7Nnz4p79+6JTZs2icKFC6f7fh89elQAEDdv3kz38UNCQoRCoRAPHz5M9345VnVg4/sREhNTxMSJR0Rg4H09JCMiorygoDW+AQEBwtTUVISGhkq1kydPilatWglra2thamoqKlWqJBYsWCBSUlLS7B8YGChatmwpbG1thVqtFhUqVBATJkwQYWFhGWaJjIwU/fv3F3Z2dkKtVovKlSuL/fv3S/evXLlSlChRQlhYWIg+ffqIuXPnZrrxffXqlVCpVMLc3FzExcWl+3yrV68uTE1Nha2trWjUqJHYtWtXhlmFEKJevXpi1apVQgghgoKCBABx4cKFdLdt166daNeunXQ7KChItGzZUhQpUkRYWVkJNzc3sXXr1jT7vX37Vvj6+ooqVaoItVotChcuLOrXry/Wr18vkpOT35vvYzx69Ei0adNGmJmZicKFC4tRo0aJt2/fSveHhIQIAOL48eNSbdKkScLR0VEolUpRrlw58eOPP+r8QZSqR48ewsPDI8PHnjdvnmjZsmWG98vR+CqEyGCGewEVGxsLa2trxCx0gtXYsGwf5/btl+jZcyeCgyPg7FwI164N46WGiYgKgLdv3yIkJASlS5dO96QnKngOHDiACRMm4Pr16zAy4tREfUhMTES5cuWwdetW1K9fP91t3vezJvVrMTHvXbkiq/juZpEQAqtWBaFmzZ8RHPxuKZAXL+Jx5sxjmZMRERFRdnh5eWHo0KEF6jLMcnv06BGmTZuWYdMrF67qkAXPn8dj0KC92Lfvnwn7FSvaY8uWLqheXaalboiIiOijffnll3JHKFDKly//0Uva5QQ2vpl06NA99Ou3B8+e/XPm5YgRbpg/3xPm5umfyUhEREREeQcb3w9ISEjG5MlHsWTJBanm4GAOf/8OaNs27/0lQ0RERETpY+P7AWFhcVi79p9197y8ysHfvz0cHS1lTEVERDnNwM79Jsp1cvyM8eS2D3B1LYwlS1pDrTbBsmWtsX9/Dza9REQFWOpVvpKSkmROQlSwpf6Mve/KevrGEd//CAuLg42N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",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.metrics import auc, roc_curve\n",
    "\n",
    "pred =  forward(dataset[test_index][:, :-1], weights, biases, actv) \n",
    "fpr, tpr, thresholds = roc_curve(dataset[test_index][:, -1], pred)\n",
    "\n",
    "roc_auc = auc(fpr, tpr)\n",
    "\n",
    "# 7. 绘制ROC曲线\n",
    "plt.figure(figsize=(8, 6))\n",
    "# 绘制ROC曲线\n",
    "plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC curve (AUC = {roc_auc:.2f})')\n",
    "# 绘制随机猜测的基准线（AUC=0.5）\n",
    "plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')\n",
    "# 设置坐标轴范围和标签\n",
    "plt.xlim([0.0, 1.0])\n",
    "plt.ylim([0.0, 1.05])\n",
    "plt.xlabel('False Positive Rate (FPR)')\n",
    "plt.ylabel('True Positive Rate (TPR)')\n",
    "plt.title('Receiver Operating Characteristic (ROC) Curve')\n",
    "plt.legend(loc=\"lower right\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "a9294f94",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "准确率[0.93] 交叉熵0.23016758857670042\n"
     ]
    }
   ],
   "source": [
    "pred = forward(dataset[test_index][:, :-1], weights, biases, actv)\n",
    "\n",
    "print(f\"准确率{sum((pred >0.5) ==  dataset[test_index][:, -1].reshape((-1, 1))) / len(pred)} 交叉熵{bce(pred, dataset[test_index][:, -1].reshape((-1, 1)))}\") "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "ef63734c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((200,), (200,))"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dataset[test_index][:, -1].astype(int).shape, pred.flatten().shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31e05440",
   "metadata": {},
   "source": [
    "### 性能测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f1534def",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "for _ in range(20):\n",
    "    weights = [np.ones((3, 32)), np.ones((32, 50)), np.ones((50, 1))]\n",
    "    biases = [np.zeros((1, 32)), np.zeros((1, 50)), np.zeros((1, 1))]\n",
    "    arc_actv = [relu, relu, arc_sigmoid]\n",
    "    actv = [relu, relu, sigmoid]\n",
    "\n",
    "\n",
    "    for epoch in range(10):\n",
    "        loss_array = []\n",
    "        for x, y in batch_data(dataset[train_index], 50):\n",
    "            #print(x.shape, y.shape)\n",
    "            solve_network(x, y.reshape((-1, 1)), weights, biases, arc_actv, actv, 0.5)\n",
    "            p = forward(x, weights, biases, actv) \n",
    "            loss_array.append(bce(p, y.astype(int).reshape((-1, 1))))\n",
    "    # print(np.array(loss_array).mean())\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c06c182",
   "metadata": {},
   "source": [
    "### 与梯度方法对照"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e4d843e4",
   "metadata": {},
   "outputs": [],
   "source": [
    "class simple_mlp:\n",
    "    def __init__(self, in_dim, out_dim, hidden_layers):\n",
    "        self.weights = []\n",
    "        self.weights.append(np.random.randn(in_dim + 1, hidden_layers[0]))\n",
    "        for i in range(len(hidden_layers)-1):\n",
    "            self.weights.append(np.random.randn(hidden_layers[i]+ 1, hidden_layers[i+1]) )\n",
    "        self.weights.append(np.random.randn(hidden_layers[-1] + 1, out_dim))\n",
    "        self.z = []\n",
    "    \n",
    "    def forward(self, x):\n",
    "        self.z.clear()\n",
    "        for w in self.weights[:-1]:\n",
    "            z = np.c_[x, np.ones((x.shape[0], 1))] @ w\n",
    "            self.z.append(z)\n",
    "            x = relu(z)\n",
    "        z = np.c_[x, np.ones((x.shape[0], 1))] @ self.weights[-1]\n",
    "        self.z.append(z)\n",
    "        return sigmoid(z)\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5a41c7b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "def relu(x):\n",
    "    return np.maximum(0, x)\n",
    "\n",
    "def relu_derivative(x):\n",
    "    return (x > 0).astype(float)\n",
    "\n",
    "def sigmoid(x):\n",
    "    return 1 / (1 + np.exp(-x))\n",
    "\n",
    "class simple_mlp:\n",
    "    def __init__(self, in_dim, out_dim, hidden_layers):\n",
    "        self.weights = []\n",
    "        # 输入层到第一层隐藏层（含偏置）\n",
    "        self.weights.append(np.random.randn(in_dim + 1, hidden_layers[0]))\n",
    "        # 隐藏层之间（含偏置）\n",
    "        for i in range(len(hidden_layers)-1):\n",
    "            self.weights.append(np.random.randn(hidden_layers[i] + 1, hidden_layers[i+1]))\n",
    "        # 最后一层隐藏层到输出层（含偏置）\n",
    "        self.weights.append(np.random.randn(hidden_layers[-1] + 1, out_dim))\n",
    "        self.z = []  # 存储各层线性输出（未激活）\n",
    "        self.activations = []  # 新增：存储各层激活后输出（含输入层）\n",
    "\n",
    "    def forward(self, x):\n",
    "        self.z.clear()\n",
    "        self.activations.clear()\n",
    "        self.activations.append(x)  # 输入层作为初始激活值\n",
    "        \n",
    "        # 前向传播通过隐藏层\n",
    "        for w in self.weights[:-1]:\n",
    "            # 添加偏置项（全为1的列）\n",
    "            x_with_bias = np.c_[x, np.ones((x.shape[0], 1))]\n",
    "            z = x_with_bias @ w  # 线性输出\n",
    "            self.z.append(z)\n",
    "            x = relu(z)  # ReLU激活\n",
    "            self.activations.append(x)\n",
    "        \n",
    "        # 输出层（sigmoid激活）\n",
    "        x_with_bias = np.c_[x, np.ones((x.shape[0], 1))]\n",
    "        z = x_with_bias @ self.weights[-1]\n",
    "        self.z.append(z)\n",
    "        output = sigmoid(z)\n",
    "        self.activations.append(output)\n",
    "        return output\n",
    "\n",
    "    def backward(self, x, y_true, learning_rate):\n",
    "        \"\"\"\n",
    "        反向传播计算梯度并更新权重\n",
    "        参数:\n",
    "            x: 输入数据 (batch_size, in_dim)\n",
    "            y_true: 真实标签 (batch_size, out_dim)\n",
    "            learning_rate: 学习率\n",
    "        返回:\n",
    "            损失值\n",
    "        \"\"\"\n",
    "        batch_size = x.shape[0]\n",
    "        y_pred = self.forward(x)  \n",
    "        \n",
    "        delta = y_pred - y_true  # (batch_size, out_dim)\n",
    "        \n",
    "        # 存储各层权重的梯度\n",
    "        weight_grads = []\n",
    "        \n",
    "        last_hidden_activation = self.activations[-2]  # 最后一层隐藏层的激活值\n",
    "        last_hidden_with_bias = np.c_[last_hidden_activation, np.ones((batch_size, 1))]  # 加偏置\n",
    "        # 计算权重梯度 (hidden_dim+1, out_dim)\n",
    "        grad = (last_hidden_with_bias.T @ delta) / batch_size  # 除以batch_size求平均\n",
    "        weight_grads.append(grad)\n",
    "        \n",
    "        # 3. 处理隐藏层之间的权重（从后往前）\n",
    "        for i in reversed(range(len(self.weights) - 1)):\n",
    "            # 当前权重对应的线性输出z\n",
    "            z = self.z[i]\n",
    "            # ReLU导数\n",
    "            relu_grad = relu_derivative(z)  # (batch_size, hidden_dim)\n",
    "            \n",
    "            # 去除偏置对应的权重，计算误差传递\n",
    "            weights_without_bias = self.weights[i+1][:-1, :]  # 去掉偏置行\n",
    "            delta = (delta @ weights_without_bias.T) * relu_grad  # 误差传递到当前层\n",
    "            \n",
    "            # 计算当前层权重梯度\n",
    "            prev_activation = self.activations[i]  # 前一层的激活值\n",
    "            prev_with_bias = np.c_[prev_activation, np.ones((batch_size, 1))]  # 加偏置\n",
    "            grad = (prev_with_bias.T @ delta) / batch_size  # 除以batch_size求平均\n",
    "            weight_grads.append(grad)\n",
    "        \n",
    "        # 4. 反转梯度顺序（与权重顺序一致）\n",
    "        weight_grads = weight_grads[::-1]\n",
    "        \n",
    "        # 5. 梯度下降更新权重\n",
    "        for i in range(len(self.weights)):\n",
    "            self.weights[i] -= learning_rate * weight_grads[i]\n",
    "        \n",
    "        # 计算并返回交叉熵损失\n",
    "        loss = -np.mean(y_true * np.log(y_pred + 1e-8) + (1 - y_true) * np.log(1 - y_pred + 1e-8))\n",
    "        return loss\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "55879079",
   "metadata": {},
   "outputs": [],
   "source": [
    "nn = simple_mlp(3, 1, hidden_layers=[32, 50])\n",
    "mean_loss2 = []\n",
    "for epoch in range(50):\n",
    "    loss_array = []\n",
    "    for x, y in batch_data(dataset[train_index], 50):\n",
    "\n",
    "        loss_array.append(nn.backward(x, y, learning_rate=1e-3))\n",
    "    mean_loss2.append(np.array(loss_array).mean())\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "plt.plot(range(len(mean_loss2)), mean_loss2)\n",
    "plt.xlabel(\"epochs\")\n",
    "plt.ylabel(\"bce loss\")\n",
    "plt.title(\"gradient method with lr=0.001 in 50 epochs\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22ce0be5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "plt.plot(range(len(mean_loss1)), mean_loss1)\n",
    "plt.plot(range(len(mean_loss2)), mean_loss2)\n",
    "plt.xlabel(\"epochs\")\n",
    "plt.ylabel(\"bce loss\")\n",
    "plt.title(\"comparing\")\n",
    "plt.legend([\"non-gradient methond\", \"gradient backward method\"])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a4328369",
   "metadata": {},
   "outputs": [],
   "source": [
    "pred = nn.forward(dataset[test_index][:, :-1])\n",
    "fpr, tpr, thresholds = roc_curve(dataset[test_index][:, -1], pred)\n",
    "\n",
    "roc_auc = auc(fpr, tpr)\n",
    "\n",
    "# 7. 绘制ROC曲线\n",
    "plt.figure(figsize=(8, 6))\n",
    "# 绘制ROC曲线\n",
    "plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC curve (AUC = {roc_auc:.2f})')\n",
    "# 绘制随机猜测的基准线（AUC=0.5）\n",
    "plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')\n",
    "# 设置坐标轴范围和标签\n",
    "plt.xlim([0.0, 1.0])\n",
    "plt.ylim([0.0, 1.05])\n",
    "plt.xlabel('False Positive Rate (FPR)')\n",
    "plt.ylabel('True Positive Rate (TPR)')\n",
    "plt.title('Receiver Operating Characteristic (ROC) Curve')\n",
    "plt.legend(loc=\"lower right\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d83a7a04",
   "metadata": {},
   "outputs": [],
   "source": [
    "p = nn.forward(dataset[test_index][:, :-1])\n",
    "\n",
    "print(f\"准确率{sum((p > 0.5) == dataset[test_index][:, -1].reshape((-1, 1)))/ len(p)}  交叉熵 {bce(p, dataset[test_index][:, -1].reshape((-1, 1)))}\")\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fff54a21",
   "metadata": {},
   "source": [
    "### 梯度方法 耗时"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6f9de32e",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "for _ in range(20):\n",
    "    nn = simple_mlp(3, 1, hidden_layers=[32, 50])\n",
    "\n",
    "    for epoch in range(50):\n",
    "        loss_array = []\n",
    "        for x, y in batch_data(dataset[train_index], 50):\n",
    "\n",
    "            loss_array.append(nn.backward(x, y, learning_rate=1e-3))\n",
    "\n",
    "\n",
    "        #print(np.array(loss_array).mean())"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
